#include "board.h"
#include "ui_manager.h"
#include "msg_manager.h"
#include "esp_log.h"
#include <inttypes.h>

#define TAG "UI_MANAGER"

extern lv_obj_t*  sys_main_interface_ui_init(void);
extern lv_obj_t*  sys_main_lvgl_register(void);
extern lv_obj_t*  lcmusic_lvgl_register(void);
extern lv_obj_t*  record_lvgl_register(void);

static ui_manager_context_t global_ui_manager;
ui_manager_context_t  *ui_manager_context;

ui_view_lvgl_t view_lvgl_list[] = {
	{MAIN_VIEW, NULL, sys_main_interface_ui_init},
	{MENU_VIEW, NULL, sys_main_lvgl_register},
	{LCMUSIC_VIEW, NULL, lcmusic_lvgl_register},
	{RECORD_VIEW, NULL, record_lvgl_register},
};

static ui_manager_context_t *_ui_manager_get_context(void)
{
	return ui_manager_context;
}

static void _ui_manager_add_view(ui_view_context_t *view)
{
	ui_view_context_t *cur_view;
	ui_view_context_t *pre_view = NULL;
	ui_manager_context_t *ui_manager = _ui_manager_get_context();

	SYS_SLIST_FOR_EACH_CONTAINER(&ui_manager->view_list, cur_view, node) {
		if (view->info.order > cur_view->info.order) {
			sys_slist_insert(&ui_manager->view_list, &pre_view->node, &view->node);
			goto end;
		}
		pre_view = cur_view;
	}

	sys_slist_append(&ui_manager->view_list, (sys_snode_t *)view);

end:
	return;
}

static ui_view_context_t *_ui_manager_get_view_context(uint8_t view_id)
{
	ui_view_context_t *view;

	ui_manager_context_t *ui_manager = _ui_manager_get_context();

	SYS_SLIST_FOR_EACH_CONTAINER(&ui_manager->view_list, view, node) {
		if (view->view_id == view_id)
			return view;
	}

	return NULL;
}

#if 0
static int _ui_manager_get_view_index(uint8_t view_id)
{
	ui_manager_context_t *ui_manager = _ui_manager_get_context();
	ui_view_context_t *view;
	int  index = 0;

	SYS_SLIST_FOR_EACH_CONTAINER(&ui_manager->view_list, view, node) {
		if (view->view_id == view_id) {
			break;
		}
		index += 1;
	}

	return index;
}
#endif

bool ui_view_create(uint8_t view_id, ui_view_info_t *info)
{
	ui_view_context_t *view;

	view = _ui_manager_get_view_context(view_id);
	if (view) {
        ESP_LOGE(TAG, "view %d already exist", view_id);
        return false;
    }
		
	view = malloc(sizeof(ui_view_context_t));
	if (!view) {
        ESP_LOGE(TAG, "malloc failed");
        return false;
    }

	memset(view, 0, sizeof(ui_view_context_t));

	view->view_id = view_id;
	view->task_name = info->task_name;

	memcpy(&view->info, info, sizeof(ui_view_info_t));

	for (int i = 0; i < sizeof(view_lvgl_list) / sizeof(ui_view_lvgl_t); i++) {
		if (view_lvgl_list[i].view_id == view_id) {
			view->info.src_obj = view_lvgl_list[i].lv_obj;
			break;
		}
	}

	_ui_manager_add_view(view);

	ui_message_send_async(view_id, MSG_VIEW_CREATE, 0);

	return true;
}

bool ui_view_delete(uint8_t view_id)
{
	ui_manager_context_t *ui_manager = _ui_manager_get_context();
	ui_view_context_t *view = _ui_manager_get_view_context(view_id);

	if (!view) {
        ESP_LOGE(TAG, "view %d not exist", view_id);
        return false;
    }

	view->info.view_proc(view->view_id, MSG_VIEW_DELETE, 0);

	sys_slist_find_and_remove(&ui_manager->view_list, &view->node);

	free(view);

	return true;
}

int ui_message_send_async(uint8_t view_id, uint32_t msg_id, uint32_t msg_data)
{
	struct app_msg msg = {0};
	ui_view_context_t *view = _ui_manager_get_view_context(view_id);

	if (!view) {
		return -1;
	}

	msg.type = MSG_UI_EVENT;
	msg.sender = view_id;
	msg.cmd = msg_id;
	msg.value = msg_data;
	ESP_LOGI(TAG, "view_id %d  msg_id %lu  msg_data %lu\n", view_id, msg_id,  msg_data);

	return msg_manager_send_async_msg(MAIN_TASK_NAME, &msg);
}

int ui_message_dispatch(uint8_t view_id, uint32_t msg_id, uint32_t msg_data)
{
	ui_view_context_t *view = _ui_manager_get_view_context(view_id);

	if (!view) {
		return -1;
	}

	return view->info.view_proc(view->view_id, msg_id, msg_data);
}

int ui_manager_load_acr_anim(uint8_t view_id, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del)
{
	ui_view_context_t *view = _ui_manager_get_view_context(view_id);
	if (!view) {
		return -1;
	}

	// printf("src_obj: %p\n", view->info.src_obj);
	lv_img_cache_invalidate_src(NULL);
	// lv_scr_load(view->info.src_obj);
	lv_scr_load_anim(view->info.src_obj, anim_type, time, delay, auto_del);

	return 0;
}

int ui_manager_dispatch_key_event(uint32_t key_event)
{
	ui_manager_context_t *ui_manager = _ui_manager_get_context();
	ui_view_context_t *view = NULL;
	uint8_t index = 0;
	int result = 0;
	uint32_t current_state = 0xffffffff;
	uint32_t key_type = key_event & 0xffff0000;
	uint16_t key_code = key_event & 0xffff;
	struct app_msg new_msg = { 0 };

	SYS_SLIST_FOR_EACH_CONTAINER(&ui_manager->view_list, view, node) {
		const ui_key_map_t *view_key_map = view->info.view_key_map;

		index = 0;
		current_state = 0xffffffff;
		if (view->info.view_get_state) {
            current_state = view->info.view_get_state();
        }

		while (view_key_map[index].key_code != KEY_RESERVED) {
			if (key_code == view_key_map[index].key_code) {
				if (view_key_map[index].app_state == TRANSMIT_ALL_KEY_EVENT && (key_type & view_key_map[index].key_type)) {
					new_msg.type = MSG_INPUT_EVENT;
					new_msg.value = key_event;
					result = msg_manager_send_async_msg(view->task_name, &new_msg);

					return result;
				} else if ((key_type & view_key_map[index].key_type) && (current_state & view_key_map[index].app_state)) {
					new_msg.type = MSG_INPUT_EVENT;
					new_msg.cmd = view_key_map[index].msg_cmd;
					result = msg_manager_send_async_msg(view->task_name, &new_msg);
                    
					return result;
				}
			}
			index++;
		}
	}
	return result;
}

int ui_manager_init(void)
{
	if (ui_manager_context)
		return -1;

	ui_manager_context = &global_ui_manager;

	memset(ui_manager_context, 0, sizeof(ui_manager_context_t));

	sys_slist_init(&ui_manager_context->view_list);

	for (int i = 0; i < sizeof(view_lvgl_list) / sizeof(ui_view_lvgl_t); i++) {
		ui_view_lvgl_t* view_lvgl = &view_lvgl_list[i];
		view_lvgl->lv_obj = view_lvgl->lvgl_register();
		// printf("src_obj: %p\n", view_lvgl->lv_obj);
	}

	return 0;
}
